﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Web.Mvc;
using MvcContrib.UI.Grid;

namespace etcetera.Mvc.UI.Grid
{
    /// <summary>
    /// 
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class GridEx<T> : Grid<T>, IGridEx<T> where T : class
    {
        private readonly TextWriter _writer;
        private readonly ViewContext _context;
        private string _title;
        private string _gridId;
        private bool _withToggle = true;
        private bool _startOpen = true;
        private IDictionary<string, object> _headerAttributes = new Dictionary<string, object>();

        /// <summary>
        /// Initializes a new instance of the <see cref="GridEx&lt;T&gt;"/> class.
        /// </summary>
        /// <param name="dataSource">The datasource for the grid</param>
        /// <param name="writer">The TextWriter where the grid should be rendered</param>
        /// <param name="context"></param>
        public GridEx(IEnumerable<T> dataSource, TextWriter writer, ViewContext context) : base(dataSource, writer, context)
        {
            _writer = writer;
            _context = context;
            Model.Renderer = new HtmlGridRenderer<T>();
        }

        public new void Render()
        {
            RenderGridContainerStart();
            Model.Renderer.Render(Model, DataSource, _writer, _context);
            RenderGridContainerEnd();
        }

        public new IGridEx<T> RenderUsing(IGridRenderer<T> renderer)
        {
            Model.Renderer = renderer;
            return this;
        }

        public new IGridEx<T> Columns(Action<ColumnBuilder<T>> columnBuilder)
        {
            base.Columns(columnBuilder);
            return this;
        }

        public IGridEx<T> ColWidth(params string[] widths)
        {
            if (Model.Renderer is HtmlGridRenderer<T>)
                ((HtmlGridRenderer<T>)Model.Renderer).ColWidths = widths;

            return this;
        }

        public IGridEx<T> HeaderAttributes(IDictionary<string, object> headerAttributes)
        {
            _headerAttributes = headerAttributes;
            return this;
        }

        public new IGridEx<T> Attributes(IDictionary<string, object> attributes)
        {
            base.Attributes(attributes);
            return this;
        }

        public new IGridEx<T> Empty(string emptyText)
        {
            Model.EmptyText = emptyText;
            return this;
        }

        public override string ToString()
        {
            Render();

            return null;
        }

        private void RenderGridContainerStart()
        {
            /*
            <div class="grid">
                <div class="gridHeader">
                    <div class="gridTitle">TITLE</div>
                    <div class="gridToggle" id="btnSlide"><span /></div>
                </div>

                <div class="gridData" id="data">
                    <table class="tblGrid">
             */

            RenderText("<!-- GridEx Start -->");
            
            if (_withToggle)
                RenderToggleScript();

            RenderText(string.Format("<div {0}>", "class=\"grid\""));
            
            if (!string.IsNullOrEmpty(_title))
            {
                string headerClass = "gridHeader";
                if (_headerAttributes != null && _headerAttributes.ContainsKey("class"))
                {
                    // Merge the class names
                    headerClass += " " + _headerAttributes["class"];
                    _headerAttributes.Remove("class");
                }
                string attr = BuildHtmlAttributes(_headerAttributes);
                if (!string.IsNullOrEmpty(attr))
                    attr += " " + attr;
                
                RenderText(string.Format("<div class=\"{0}\"{1}>", headerClass, attr));
                RenderText(string.Format("<div class=\"{0}\">{1}</div>", "gridTitle", _title));

                if (_withToggle)
                    RenderText(string.Format("<div class=\"{0}\" id=\"{1}{2}\"><span></span></div>", "gridToggle", "btnSlide", _gridId));

                RenderText("</div>");
            }
            
            string style = string.Empty;
            if (!_startOpen)
                style = " style=\"display: none;\"";
            RenderText(string.Format("<div class=\"{0}\" id=\"{1}{2}\"{3}>", "gridData", "data", _gridId, style));
        }

        private void RenderGridContainerEnd()
        {
            RenderText("</div>");
            RenderText("</div>");
            RenderText("<!-- GridEx Stop -->");
        }

        private void RenderToggleScript()
        {
            /*
            <script type="text/javascript">
                $(document).ready(function() {
                    $("#btnSlideC").toggleClass("gridToggleActive");
                    $("#btnSlideC").click(function() {
                        $("#dataC").slideToggle("slow");
                        $(this).toggleClass("gridToggleActive");
                        return false;
                    });
                });
            </script>
            */
            RenderText("<script type=\"text/javascript\">");
            RenderText("$(document).ready(function() {");
            if (!_startOpen)
                RenderText(string.Format("$(\"#btnSlide{0}\").toggleClass(\"gridToggleActive\");", _gridId));
            RenderText(string.Format("$(\"#btnSlide{0}\").click(function() {{", _gridId));
            RenderText(string.Format("$(\"#data{0}\").slideToggle(\"slow\");", _gridId));
            RenderText("$(this).toggleClass(\"gridToggleActive\");");
            RenderText("return false;");
            RenderText("});");
            RenderText("});");
            RenderText("</script>");
        }

        protected void RenderText(string text)
        {
            _writer.Write(text);
        }

        public IGridEx<T> Titled(string title)
        {
            _title = title;
            return this;
        }

        public IGridEx<T> WithId(string gridId)
        {
            _gridId = gridId;
            ((HtmlGridRenderer<T>)Model.Renderer).GridId = gridId;
            return this;
        }

        public IGridEx<T> WithToolStripId(string id)
        {
            if (Model.Renderer is HtmlGridRenderer<T>)
                ((HtmlGridRenderer<T>)Model.Renderer).PagerId = id;
            return this;
        }

        public IGridEx<T> WithToggle(bool withToggle)
        {
            return WithToggle(withToggle, true);
        }

        public IGridEx<T> WithToggle(bool withToggle, bool startOpen)
        {
            _withToggle = withToggle;
            _startOpen = startOpen;
            return this;
        }

        public IGridEx<T> SortQueryStringName(string sortQueryStringName)
        {
            ((HtmlGridRenderer<T>)Model.Renderer).SortQueryStringName = sortQueryStringName;
            return this;
        }

        public IGridEx<T> SortOrderQueryStringName(string sortOrderQueryStringName)
        {
            ((HtmlGridRenderer<T>)Model.Renderer).SortOrderQueryStringName = sortOrderQueryStringName;
            return this;
        }

        /// <summary>
        /// Converts the specified attributes dictionary of key-value pairs into a string of HTML attributes. 
        /// </summary>
        /// <returns></returns>
        private static string BuildHtmlAttributes(IDictionary<string, object> attributes)
        {
            if (attributes == null || attributes.Count == 0)
            {
                return string.Empty;
            }

            const string attributeFormat = "{0}=\"{1}\"";

            return string.Join(" ", attributes.Select(pair => string.Format(attributeFormat, pair.Key, pair.Value)).ToArray());
        }

    }
}
